package com.baoteng.base.component;

import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Looper;
import android.os.MessageQueue;
import android.os.Process;
import android.util.Log;

import com.baoteng.base.permission.PermissionHelper;
import com.baoteng.component.lifecycle.AppObserver;
import com.baoteng.component.log.TLog;
import com.baoteng.thread.PriorityThreadFactory;
import com.baoteng.thread.ThreadDispatcher;
import com.baoteng.utils.process.ProcessUtils;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public abstract class BaseApp extends Application {

    private static BaseApp app;
    private static final int GC_CALL_DELAY = 15000;
    private ScheduledExecutorService mExec = Executors.newSingleThreadScheduledExecutor(new PriorityThreadFactory() {
        @Override
        protected int getThreadPriority() {
            return Process.THREAD_PRIORITY_LOWEST;
        }
    });
    private boolean mGcRunning;

    public static BaseApp getInstance() {
        return app;
    }

    /**
     * 由于涉及到多进程的时候,onCreate会在每个进程初始化的时候被调用,可能需要对不同进程做一些处理,
     * 比如:有的模块只需在主进程中执行初始化,而无需在其他子进程中调用.
     * 第三方进程的初始化请写在第三方进程里面
     * 请重写{@link #onCreate(boolean)}
     */
    @Override
    final public void onCreate() {
        super.onCreate();
        app = this;
        // 试运行:每隔固定时间,在消息队列闲时执行GC,降低内存峰值
        mExec.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                if (mGcRunning)
                    return;
                mGcRunning = true;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    Looper.getMainLooper().getQueue().addIdleHandler(new MessageQueue.IdleHandler() {
                        @Override
                        public boolean queueIdle() {
                            Runtime.getRuntime().gc();
                            mGcRunning = false;
                            return false;
                        }
                    });
                }
            }
        }, GC_CALL_DELAY, GC_CALL_DELAY, TimeUnit.MILLISECONDS);

        // 观察App前后台状态的模块
        AppObserver.getInstance().init(this);
        asyncInitTLog();
        // RSA加解密目前没有使用,不初始化,减少启动时间
        //RSAUtils.RSAPublicKeyHolder.getInstance().init(getApplication());
        boolean isMainProcess = ProcessUtils.isMainProcess(this);
        onCreate(isMainProcess);
    }

    private void asyncInitTLog() {
        ThreadDispatcher.getDispatcher().postHighPriority(new Runnable() {
            @Override
            public void run() {
                TLog.init(true);
            }
        });
    }

    /**
     * onCreate回调进程信息
     *
     * @param isMainProcess 是否为当前应用的主进程
     */
    public void onCreate(boolean isMainProcess) {
        if (isMainProcess) {
            // 主进程相关操作
            receiverExitBroadcast();
        }
        if ((isAllPermissionAgree())
                && isMainProcess) {
            initLibs();
        }
    }

    private boolean isAllPermissionAgree() {
        if (getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.M) {
            return true;
        }
        return PermissionHelper.isAllPermissionAgree(this, PermissionHelper.MUST_PERMISSION, allNeedPermissions());
    }

    public abstract String[] allNeedPermissions();

    /**
     * 第三方进程的初始化请写在第三方进程里面
     * 参考AppUpdateService
     */
    public void initLibs() {
        TLog.i("---------BaseApp initLibs-------------");
    }

    public abstract Class<?> firstActivity();

    private void receiverExitBroadcast() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("close_app");
        intentFilter.addAction(getPackageName());
        registerReceiver(receiver, intentFilter);
    }

    private BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            exitApp();
        }
    };

    protected void exitApp() {
        android.os.Process.killProcess(android.os.Process.myPid());
    }

    protected void killSelfOnLowMemory() {
        if (!AppObserver.getInstance().isForeground()) {
            Log.e(getClass().getName(), "onLowMemory, this application is on low memory and not a foreground process, kill self now");
            AppObserver.getInstance().closeAllActivitiesAndExit();
        } else {
            Log.e(getClass().getName(), "onLowMemory, this application is on low memory and is a foreground process");
        }
    }

    protected boolean needKillSelfOnLowMemory() {
        return false;
    }

    protected void doKillSelfOnLowMemoryBefore() {
    }

    protected void doKillSelfOnTrimMemoryBefore(int level) {
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        doKillSelfOnLowMemoryBefore();
        if (needKillSelfOnLowMemory()) killSelfOnLowMemory();
    }

    @Override
    public void onTrimMemory(int level) {
        super.onTrimMemory(level);
        doKillSelfOnTrimMemoryBefore(level);
        if (level == ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
                //表示手机目前内存已经很低了，系统准备开始根据LRU缓存来清理进程。
                // 这个时候我们的程序在LRU缓存列表的最近位置，是不太可能被清理掉的，
                // 但这时去释放掉一些比较容易恢复的资源能够让手机的内存变得比较充足，
                // 从而让我们的程序更长时间地保留在缓存当中，这样当用户返回我们的程序时会感觉非常顺畅，
                // 而不是经历了一次重新启动的过程。
                || level == ComponentCallbacks2.TRIM_MEMORY_MODERATE
                //表示手机目前内存已经很低了，并且我们的程序处于LRU缓存列表的中间位置，
                // 如果手机内存还得不到进一步释放的话，那么我们的程序就有被系统杀掉的风险了。
                || level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
            //表示手机目前内存已经很低了，并且我们的程序处于LRU缓存列表的最边缘位置，
            // 系统会最优先考虑杀掉我们的应用程序，在这个时候应当尽可能地把一切可以释放的东西都进行释放。
            Log.e(getClass().getName(), "onTrimMemory TRIM_MEMORY_BACKGROUND or TRIM_MEMORY_COMPLETE");
            if (needKillSelfOnLowMemory()) killSelfOnLowMemory();
        }
    }
}
